/*******************************************************************************
 * Copyright (c) 2011 Irineu Martins de Lima Moura (imlm2).
 * This file is part of JBeat.
 * 
 *     JBeat is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     JBeat is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with JBeat.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Contributors:
 *     Irineu Martins de Lima Moura (imlm2) - initial API and implementation
 ******************************************************************************/
package br.ufpe.cin.imlm2.jbeat;

import java.util.ArrayList;
import java.util.List;

import br.ufpe.cin.imlm2.util.options.Option;
import br.ufpe.cin.imlm2.util.options.OptionsParser;

public class JBeatOptions extends OptionsParser {

	public static final String RUNTIME_EXCEPTIONS = "runtimeExceptions";
	public static final String CLASS_PATH = "classPath";
	public static final String CP = "cp";
	public static final String HAND_INSP = "handInsp";
	public static final String HANDLER_INSPECTION = "handlerInspection";

	public static final String CALLGRAPH = "callGraph";
	public static final String VERBOSE = "verbose";
	public static final String TIME = "time";
	public static final String CLEAN_SOOT_OUTPUT = "cleanSootOutput";
	public static final String ALLOW_MISSING_DEPENDENCIES = "allowMissingDependencies";
	
	public static final String LIBRARY_PACKAGES = "libPackages";	
	public static final String APPLICATION_PACKAGES = "appPackages";

	public static final String DUMP_CLASSES = "dumpClasses";

	private JBeatOptions() {
		super( "jbeat" );
		this.addOption( new Option( HANDLER_INSPECTION, HAND_INSP,
				"Tells if a handler inspection analysis should be executed.", Boolean.TRUE ) );
		this.addOption( new Option( RUNTIME_EXCEPTIONS, "rtExcep",
				"Tells if an analysis to determine if exceptions thrown by"
						+ " the runtime instructions should be executed.", Boolean.TRUE ) );
		this.addOption( new Option( CLASS_PATH, CP,
				"Classpath for the application being analyzed.", new ArrayList<String>(),
				String.class ) );
		this.addOption( new Option( TIME, null,
				"If set to true shows soot debug output for running times.", Boolean.FALSE ) );
		this.addOption( new Option( CLEAN_SOOT_OUTPUT, "clean", "Cleans soot output on exit.",
				Boolean.TRUE ) );
		this.addOption( new Option( ALLOW_MISSING_DEPENDENCIES, "allowPhantoms",
				"Allows the analysis to go on even when there are missing dependencies.",
				Boolean.FALSE ) );
		this.addOption( new Option( DUMP_CLASSES, "dump", "Dump a lightweight version of the Scene"
				+ " containing only the analyzed classes.", Boolean.TRUE ) );

		List<Object> allowedStrings = new ArrayList<Object>();
		allowedStrings.add( "cha" );
		allowedStrings.add( "spark" );
		allowedStrings.add( "paddle" );
		this.addOption( new Option.OptionBuilder( CALLGRAPH, "spark", String.class, null ).alias(
				"cg" )
				.description(
						"Callgraph type to be used." + " Allowed values are 'cha', 'spark' and "
								+ "'paddle'." )
				.allowedValues( allowedStrings )
				.build() );
		this.addOption(new Option(LIBRARY_PACKAGES, null, "Mark all classes in packages with names" +
				" contained in the list as LIBRARY classes.",
				new ArrayList<String>(), String.class));
		this.addOption(new Option(APPLICATION_PACKAGES, null, "Mark all classes in the package names contained in the list as APPLICATION classes." +
				"By default any class not in the Java Standard libraries is an application class. This option can be used" +
				" to mark classes in the Java Standard libraries as application classes", 
				new ArrayList<String>(), String.class));
		this.setUsage( "USAGE:\n"
				+ " java -jar jbeat.jar MainClass options* \n"
				+ "WHERE:\n"
				+ "\tMainClass is the class containing the target application entry point main method.\n"
				+ "\toptions* is zero or more arguments for the analysis, the throwable set report and the class dump.\n"
				+ "NOTES:\n- Arguments are CASE SENSITIVE (i.e. true !=  TrUe).\n"
				+ "- If the target.libraries system property is defined then it should contain a list of classpath "
				+ "entries (directories and jars separated by OS specific path separators) of the Java Runtime Libraries that are going to be used by the target program."
				+ " In this case the Java Runtime Libraries should NOT be included in the "
				+ "classpath paramater.\n- Lists are SEMI-COLLON(';') separated.\n- An argument of the form '--argName' is equivalent to '--argName:true'" );
	}

	private static JBeatOptions INSTANCE;

	public static JBeatOptions getInstance() {
		if ( INSTANCE == null )
			INSTANCE = new JBeatOptions();
		return INSTANCE;
	}

	public boolean isHandlerInspection() {
		return (Boolean) this.getOptionInternal( HAND_INSP ).getValue();
	}

	public boolean isAnalyzeRuntime() {
		return (Boolean) this.getOptionInternal( RUNTIME_EXCEPTIONS ).getValue();
	}

	@SuppressWarnings("unchecked")
	public List<String> getClasspath() {
		return (List<String>) this.getOptionInternal( CLASS_PATH ).getValue();
	}

	public boolean isVerbose() {
		return (Boolean) this.getOptionInternal( VERBOSE ).getValue();
	}

	public boolean isTime() {
		return (Boolean) this.getOptionInternal( TIME ).getValue();
	}

	public boolean isCleanSootOutput() {
		return (Boolean) this.getOptionInternal( CLEAN_SOOT_OUTPUT ).getValue();
	}

	public boolean isAllowMissingDependencies() {
		return (Boolean) this.getOptionInternal( ALLOW_MISSING_DEPENDENCIES ).getValue();
	}

	public boolean isDumpClasses() {
		return (Boolean) this.getOptionInternal( DUMP_CLASSES ).getValue();
	}
	
	@SuppressWarnings("unchecked")
	public List<String> getApplicationPackages() {
		return (List<String>) this.getOptionInternal( APPLICATION_PACKAGES ).getValue();
	}
	
	@SuppressWarnings("unchecked")
	public List<String> getLibraryPackages() {
		return (List<String>) this.getOptionInternal( LIBRARY_PACKAGES ).getValue();
	}

}
